#   Trolls Outta Luckland v1.1.0
#   Copyright 2009-2010, Gummbum
#
#   This file is part of Trolls Outta Luckland.
#
#   Trolls Outta Luckland is free software: you can redistribute it
#   and/or modify it under the terms of the GNU General Public License
#   as published by the Free Software Foundation, either version 3 of
#   the License, or (at your option) any later version.
#
#   Trolls Outta Luckland is distributed in the hope that it will be
#   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
#   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with Trolls Outta Luckland.  If not, see
#   <http://www.gnu.org/licenses/>.

__version__ = '1.1.0'

### Python imports
import os
from os.path import join as join_path
import sys
import random
from random import randrange as rand

try:
    ### Pygame imports
    import pygame
    ### Game library imports
    import game_globals
    from game_globals import *
    from utils import load_image
    from vec2d import *
except ImportError, e:
    print 'ImportError: %s' % e
    print '    in file "%s"' % os.path.abspath(sys.argv[0])

# Initialized by Sky class constructor
game = None

# These are NASA and art pics in the public domain.
_PLANET_PICS = [
    'PIA01666.png',
    'PIA01667.png',
    'PIA10102.png',
    'PIA10103.png',
    'PIA11667.png',
    'Saturn_from_Cassini_Orbiter_(2004-10-06).png',
]
_GALAXY_PICS = [
    '600px-Andromeda_galaxy.png',
    '800px-Hubble2005-01-barred-spiral-galaxy-NGC1300.png',
    '800px-M104_ngc4594_sombrero_galaxy_hi-res.png',
    '800px-Messier_81_HST.png',
    '8d8e6_spaceart.png',
    'HubbleInteractingGalaxyNGC60506_3.png',
    'post_1611095_1251219044_med.png',
    'spinning-galaxy.png',
]

def iround(n):
    return int(round(n))

class Sky(pygame.sprite.LayeredUpdates):
    def __init__(self, max_stars=30, max_planets=1, max_galaxies=3):
        global game
        game = game_globals.game
        pygame.sprite.LayeredUpdates.__init__(self)
        self.max_stars = max_stars
        self.max_planets = max_planets
        self.max_galaxies = max_galaxies
        self.onscreen = []
        self.reset()
    def _stars(self):
        return self.get_sprites_from_layer(0)
    def _galaxies(self):
        return self.get_sprites_from_layer(1)
    def _planets(self):
        return self.get_sprites_from_layer(2)
    def _make_star(self, randy=False):
        self.add(Star(randy=True), layer=0)
    def _make_galaxy(self, randy=False):
        random.shuffle(_GALAXY_PICS)
        for name in _GALAXY_PICS:
            if name not in self.onscreen:
                self.add(Galaxy(name, randy=True), layer=1)
                self.onscreen.append(name)
                break
    def _make_planet(self):
        random.shuffle(_PLANET_PICS)
        for name in _PLANET_PICS:
            if name not in self.onscreen:
                self.add(Planet(name), layer=2)
                self.onscreen.append(name)
                break
    def reset(self, debug=False):
        self.empty()
        del self.onscreen[:]
        for i in range(self.max_stars):
            self._make_star(randy=True)
        if debug:
            for i in range(len(self._planets()), self.max_planets):
                self._make_planet()
        for i in range(self.max_galaxies):
            self._make_galaxy(randy=True)
    def update(self, *args):
        for i in range(len(self._stars()), self.max_stars):
            if rand(0, iround(120*game.speed())) == 0:
                self._make_star()
        # 21600 yeilds approximately 3 minutes real time
        for i in range(len(self._planets()), self.max_planets):
            if rand(0, iround(21600*game.speed())) == 0:
                self._make_planet()
        # 7200 yields approximately 60 seconds real time
        for i in range(len(self._galaxies()), self.max_galaxies):
            if rand(0, iround(7200*game.speed())) == 0:
                self._make_galaxy()
        pygame.sprite.LayeredUpdates.update(self, *args)

class Star(pygame.sprite.Sprite):
    def __init__(self, *args, **kwargs):
        pygame.sprite.Sprite.__init__(self, *args)
        randy = kwargs.get('randy', False)
        self.image,self.rect = load_image(
            join_path('image','star.png'), -1, False)
        if randy:
            self.y = float(rand(game.window.rect.top, game.window.rect.bottom))
        else:
            self.y = -5.0
        self.rect.center = rand(0,game.window.rect.right), self.y
        speed = rand(0, 10) / 10.0
        self.speed = game.speed() * float(speed+0.1) / 60
        self.alpha_range = [int(round(33.0+speed*128)),]
        self.alpha_range.append(self.alpha_range[0]+64)
        self.alpha = rand(*self.alpha_range)
        self.alpha_step = 0
        self.alpha_target = self.alpha
        self.image.set_alpha(self.alpha)
    def update(self, *args):
        self.y += self.speed
        self.rect.centery = int(self.y)
        if self.y >= game.window.rect.bottom+10:
            self.kill()
        if (self.alpha_step < 0 and self.alpha <= self.alpha_target) or \
        (self.alpha_step >= 0 and self.alpha >= self.alpha_target):
            self.alpha_target = rand(*self.alpha_range)
            if self.alpha < self.alpha_target:
                self.alpha_step = rand(2,8)
            else:
                self.alpha_step = -rand(2,8)
        self.alpha += self.alpha_step
        self.image.set_alpha(self.alpha)

class Body(pygame.sprite.Sprite):
    def __init__(self, *args, **kwargs):
        """kwargs:
            image=filename
            colorkey=color, -1, or None; default -1
            alpha=0 to 255; default 255
            scale=0.0 to 1.0; default 1.0
            rotate=0 to 360; default 0
            position=(x,y)
            speed=(dx,xy)
        """
        pygame.sprite.Sprite.__init__(self, *args)
        self._load_image(kwargs.get('image'),
            kwargs.get('colorkey', -1),
            kwargs.get('alpha', 255))
        self._rotozoom(kwargs.get('rotate', 0), kwargs.get('scale', 1.0))
        self._position(kwargs.get('position'))
        self._speed(kwargs.get('speed'))
    def _load_image(self, name, colorkey, alpha):
        self.image,rect = load_image(join_path('image',name), colorkey, False)
        self.image.set_alpha(alpha)
    def _rotozoom(self, rotate, scale):
        colorkey = self.image.get_colorkey()
        alpha = self.image.get_alpha()
        self.image = pygame.transform.rotozoom(self.image, rotate, scale)
        self.image.set_colorkey(colorkey)
        self.image.set_alpha(alpha)
        self.rect = self.image.get_rect()
    def _position(self, pos):
        x,y = pos
        if y < 0:
            y = -self.rect.height
        self.rect.center = x,y
        self.centerf = vec2d(x,y)
    def _speed(self, speed):
        self.speedx = speed[0]
        self.speedy = speed[1]
    def update(self, *args):
        rect = self.rect
        winrect = game.window.rect
        self.centerf += (self.speedx,self.speedy)
        rect.x = iround(self.centerf.x)
        rect.y = iround(self.centerf.y)
        if rect.top > winrect.bottom or \
           rect.right < winrect.left or \
           rect.left > winrect.right:
            game.sky.onscreen.remove(self.name)
            self.kill()

class Planet(Body):
    def __init__(self, image_filename):
        self.name = image_filename
        rotate = rand(0,90) - 45
        scale = rand(50,100) / 100.0
        x = rand(100,game.window.rect.right-100)
        y = -130
        dy = game.speed() * 0.1 * scale**2
        dx = game.speed() * 0.1 * scale**2
        dx *= random.choice((-1,1))
        Body.__init__(self,
            image=image_filename,
            rotate=rotate, scale=scale,
            position=(x,y), speed=(dx,dy)
        )

class Galaxy(Body):
    def __init__(self, image_filename, randy=False):
        self.name = image_filename
        scale = rand(50,100) / 100.0
        x = rand(64,game.window.rect.right-128)
        if randy:
            y = rand(64,game.window.rect.bottom-128)
        else:
            y = -64
        speed = rand(2,5) / 10.0
        dx = 0
        dy = game.speed() * float(speed+0.1) / 240
        Body.__init__(self,
            image=image_filename, alpha=80,
            rotate=rand(0,359), scale=scale,
            position=(x,y), speed=(dx,dy)
        )
